// DlgViewHistory.cpp : implementation file
//

#include "stdafx.h"
#include "XIE.h"
#include "DlgViewHistory.h"
#include "MainFrm.h"


// CDlgViewHistory dialog

IMPLEMENT_DYNAMIC(CDlgViewHistory, CDialog)

CDlgViewHistory::CDlgViewHistory(CWnd* pParent /*=NULL*/)
	: CDialog(CDlgViewHistory::IDD, pParent)
{
	m_pMalloc = NULL;
	SHGetMalloc(&m_pMalloc);
}

CDlgViewHistory::~CDlgViewHistory()
{
	if (m_pMalloc)
		m_pMalloc->Release();
}

void CDlgViewHistory::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_TREE_HISTORY, m_wndHistory);
}


BEGIN_MESSAGE_MAP(CDlgViewHistory, CDialog)
	ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_HISTORY, &CDlgViewHistory::OnTvnSelchangedTreeHistory)
	ON_NOTIFY(NM_CLICK, IDC_TREE_HISTORY, &CDlgViewHistory::OnNMClickTreeHistory)
	ON_WM_CREATE()
	ON_WM_NCDESTROY()
	ON_WM_SIZE()
END_MESSAGE_MAP()


// CDlgViewHistory message handlers

void CDlgViewHistory::OnTvnSelchangedTreeHistory(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
	// TODO: Add your control notification handler code here
	*pResult = 0;
}

void CDlgViewHistory::OnNMClickTreeHistory(NMHDR *pNMHDR, LRESULT *pResult)
{
	// TODO: Add your control notification handler code here
	HTREEITEM hItem;

	CPoint pt;
	try
	{
		GetCursorPos(&pt);
		ScreenToClient(&pt);
		hItem = m_wndHistory.HitTest(pt);

		if ((hItem != NULL) && !m_wndHistory.ItemHasChildren(hItem))
		{
			int nImg, nOImg;

			m_wndHistory.GetItemImage(hItem, nImg, nOImg);
			if(nImg==2)
			{
				((CMainFrame*)AfxGetMainWnd())->SmartGoNewURL(
					m_arrHistory[m_wndHistory.GetItemData(hItem)- 1]
				);				
			}
			else
			{
				//get folder
				LPITEMIDLIST pidlHistory = NULL;				
				HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_HISTORY, &pidlHistory);
				if (NOERROR != hr)
					return;

				IShellFolder* psfDesktop;
				IShellFolder* psfHistory;				
				hr = SHGetDesktopFolder(&psfDesktop);
				if (NOERROR != hr)
					return;				
				hr = psfDesktop->BindToObject(pidlHistory, NULL, IID_IShellFolder,
					(LPVOID*)&psfHistory);
				psfDesktop->Release();				
				if (NOERROR != hr)
					return;

				HTREEITEM hDayItem;
				hDayItem = m_wndHistory.GetParentItem(hItem);
				if(hDayItem == NULL)
					hDayItem = hItem;

				CString folder = m_wndHistory.GetItemText(hDayItem);
				LPITEMIDLIST pidlSubFolder = FindFolder(folder, psfHistory);
				if(pidlSubFolder!=NULL)
				{
					IShellFolder* psfSubFolder = NULL;
					IShellFolder* psfSubFolder2 = NULL;
					hr = psfHistory->BindToObject(pidlSubFolder, NULL, IID_IShellFolder,
						(LPVOID*)&psfSubFolder);					
					if( hDayItem != hItem)
					{
						if (pidlSubFolder)
							m_pMalloc->Free(pidlSubFolder);

						folder = m_wndHistory.GetItemText(hItem);
						pidlSubFolder = FindFolder(folder, psfSubFolder);
						hr = psfSubFolder->BindToObject(pidlSubFolder, NULL, IID_IShellFolder,
							(LPVOID*)&psfSubFolder2);
					}
					if(nImg ==0)
						AddHistory(psfSubFolder, hItem, 1,3);
					else
						AddHistory(psfSubFolder2, hItem, 2,2);
					if(psfSubFolder)
						psfSubFolder ->Release();
					if(psfSubFolder2)
						psfSubFolder2 ->Release();
				}
				m_pMalloc->Free(pidlSubFolder);
				m_pMalloc->Free(pidlHistory);
				psfHistory->Release();
				m_wndHistory.Expand(hItem,TVE_TOGGLE);
			}
		}
		else
			m_wndHistory.Expand(hItem,TVE_TOGGLE);
	}catch(...){}

	*pResult = 0;	
}

LPITEMIDLIST CDlgViewHistory::FindFolder(LPCTSTR foldername, IShellFolder *pFolder)
{
	IEnumIDList* pItems = NULL;
	LPITEMIDLIST pidlNext = NULL;
	STRRET StrRetName;
	LPTSTR lpszName = NULL;

	HRESULT hr = pFolder->EnumObjects(NULL, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS, &pItems);
	while (NOERROR == hr)
	{
		hr = pItems->Next(1, &pidlNext, NULL);
		if (NOERROR == hr)
		{
			pFolder->GetDisplayNameOf(pidlNext, SHGDN_NORMAL, &StrRetName);
			StrRetToStr(StrRetName, &lpszName, pidlNext);
			if(_tcscmp(foldername, lpszName) == 0)
			{
				if (lpszName)
					m_pMalloc->Free(lpszName);
				if (pItems)
					pItems->Release();
				return pidlNext;
			}
			else if (pidlNext)
				m_pMalloc->Free(pidlNext);
			if (lpszName)
				m_pMalloc->Free(lpszName);
		}
	}

	if (pItems)
		pItems->Release();

	return NULL;
}


BOOL CDlgViewHistory::Initialize()
{
	m_wndHistory.DeleteAllItems();
	m_arrHistory.RemoveAll();

	LPITEMIDLIST pidlHistory = NULL;	
	HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_HISTORY, &pidlHistory);
	if (NOERROR != hr)
		return FALSE;

	IShellFolder* psfDesktop;
	IShellFolder* psfHistory;
	hr = SHGetDesktopFolder(&psfDesktop);
	if (NOERROR != hr)
	{
		return FALSE;
	}
	hr = psfDesktop->BindToObject(pidlHistory, NULL, IID_IShellFolder,
		(LPVOID*)&psfHistory);
	psfDesktop->Release();
	if (NOERROR != hr)
	{
		return FALSE;
	}

	AddHistory(psfHistory, NULL);
	m_pMalloc->Free(pidlHistory);
	psfHistory->Release();

	return TRUE;
}
int CDlgViewHistory::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CDialog::OnCreate(lpCreateStruct) == -1)
		return -1;

	// TODO:  Add your specialized creation code here

	// bring the tooltips to front
	

	return 0;
}

BOOL CDlgViewHistory::Update(int nLevel)
{	
	//following is for ie5 and win98
	//remove the children of Today
	HTREEITEM hit;
	BOOL found=FALSE;
	CString text;
	text.LoadString(IDS_HISTORY_TODAY);

	//get today item
	hit = m_wndHistory.GetChildItem(NULL);
	while(hit != NULL && !found)
	{
		if(m_wndHistory.GetItemText(hit).CompareNoCase(text)==0)
			found = TRUE;
		else
			hit = m_wndHistory.GetNextSiblingItem(hit);
	}

	if(found)
	{
		//delete today
		m_wndHistory.DeleteItem(hit);
		//m_wndHistory.Expand(pre, TVE_COLLAPSE);
	}

	LPITEMIDLIST pidlHistory = NULL;	
	HRESULT hr = SHGetSpecialFolderLocation(NULL, CSIDL_HISTORY, &pidlHistory);
	if (NOERROR != hr)
		return FALSE;

	IShellFolder* psfDesktop;
	IShellFolder* psfHistory;	
	hr = SHGetDesktopFolder(&psfDesktop);
	if (NOERROR != hr)
		return FALSE;	
	hr = psfDesktop->BindToObject(pidlHistory, NULL, IID_IShellFolder,
		(LPVOID*)&psfHistory);
	psfDesktop->Release();	
	if (NOERROR != hr)
		return FALSE;

	AddHistory(psfHistory, NULL,0,0,TRUE);	
	m_pMalloc->Free(pidlHistory);	
	psfHistory->Release();

	return TRUE;
}

void CDlgViewHistory::AddHistory(IShellFolder *pFolder, HTREEITEM root, int nImg, int nOImg, BOOL bNeedCmp)
{
	if(pFolder == NULL)
		return;

	//enum history
	IEnumIDList* pItems = NULL;
	LPITEMIDLIST pidlNext = NULL;
	STRRET StrRetName;
	LPTSTR lpszName = NULL;
	LPTSTR lpszURL = NULL;
	DWORD dwEntrySize=0;

	// Enumerate all object in the given folder
	HRESULT hr = pFolder->EnumObjects(NULL, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN , &pItems);
	while (NOERROR == hr)
	{
		hr = pItems->Next(1, &pidlNext, NULL);
		if (NOERROR == hr)
		{
			pFolder->GetDisplayNameOf(pidlNext, SHGDN_NORMAL, &StrRetName);
			StrRetToStr(StrRetName, &lpszName, pidlNext);
			//add folder
			BOOL found = FALSE;
			if(bNeedCmp)
			{
				HTREEITEM hit;
				//get today item
				hit = m_wndHistory.GetChildItem(root);
				while(hit!=NULL && !found)
				{
					if(m_wndHistory.GetItemText(hit).CompareNoCase(lpszName)==0)
						found = TRUE;
					else
						hit = m_wndHistory.GetNextSiblingItem(hit);
				}
			}
			if(!found)
			{
				HTREEITEM hItem;
				if(nImg==0)
					hItem = m_wndHistory.InsertItem(lpszName, nImg, nOImg, root ,TVI_LAST);
				else
					hItem = m_wndHistory.InsertItem(lpszName, nImg, nOImg, root ,TVI_SORT);

				if(nImg==2)
					ResolveHistory(pFolder, pidlNext, &lpszURL);

				if (lpszURL)
				{
					// Add the URL to the array and free lpszURL
					// since it was created with IMalloc::Alloc
					m_arrHistory.Add(lpszURL);
					m_wndHistory.SetItemData(hItem, m_arrHistory.GetSize());

					//is the url cached?
					
					dwEntrySize = 0;
					if(_tcsncmp(lpszURL, _T("file:"), 5) != 0)
					{
						if (!GetUrlCacheEntryInfoEx(lpszURL,NULL,&dwEntrySize, NULL, NULL, NULL, 0))
						{
							if (GetLastError()==ERROR_FILE_NOT_FOUND)
							{
								m_wndHistory.SetItemState(hItem, TVIS_CUT, TVIS_CUT);
							}
						}
					}
					
					m_pMalloc->Free(lpszURL);
					lpszURL = NULL;
				}
			}
			if (lpszName)
				m_pMalloc->Free(lpszName);
			if (pidlNext)
				m_pMalloc->Free(pidlNext);
		}
	}
	if (pItems)
		pItems->Release();
}

BOOL CDlgViewHistory::ResolveHistory(IShellFolder* pFolder, LPCITEMIDLIST pidl, LPTSTR* lpszURL)
{
	IShellLink* pShellLink;
	*lpszURL = NULL;  // Assume failure

	// Get a pointer to the IShellLink interface from the given folder
	HRESULT hr = pFolder->GetUIObjectOf(NULL, 1, &pidl, IID_IShellLink, NULL, (LPVOID*)&pShellLink);
	if (SUCCEEDED(hr))
	{
		WIN32_FIND_DATA wfd;      
		hr = pShellLink->Resolve(AfxGetApp()->m_pMainWnd->m_hWnd, SLR_NO_UI); 
		if (NOERROR == hr)
		{
			// Get the path to the link target. 
			int cch = 1024;
			*lpszURL = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR));  // Must remember to Free later
			ZeroMemory(*lpszURL, cch * sizeof(TCHAR));
			hr = pShellLink->GetPath(*lpszURL, cch - 1, (WIN32_FIND_DATA*)&wfd, SLGP_UNCPRIORITY);
		}
		pShellLink->Release();
	}

	if(SUCCEEDED(hr))
		return TRUE;
	else
		return FALSE;
}

void CDlgViewHistory::OnNcDestroy()
{
	CDialog::OnNcDestroy();

	delete this;

	// TODO: Add your message handler code here
}

BOOL CDlgViewHistory::StrRetToStr(STRRET StrRet, LPTSTR *str, LPITEMIDLIST pidl)
{
	HRESULT hr = S_OK;
	int cch;
	LPTSTR strOffset;	
	*str = NULL;  // Assume failure
	CString strTemp;

	switch (StrRet.uType)
	{
	case STRRET_WSTR: 
		cch = _tcslen(StrRet.pOleStr) + 1; 
		*str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR));	
		if (*str != NULL)
			_tcscpy(*str, StrRet.pOleStr);
		else
			hr = E_FAIL;		
		break;

	case STRRET_OFFSET: 
		strOffset = (((TCHAR *) pidl) + StrRet.uOffset);		
		cch = _tcslen(strOffset) + 1; // NULL terminator
		*str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR));		
		if (*str != NULL)
			_tcscpy(*str, strOffset);
		else
			hr = E_FAIL;
		break;

	case STRRET_CSTR: 
		cch = strlen(StrRet.cStr) + 1; // NULL terminator
		*str = (LPTSTR)m_pMalloc->Alloc(cch * sizeof(TCHAR));
		strTemp = StrRet.cStr;
		if (*str != NULL)
			_tcscpy(*str, (LPCTSTR)strTemp);
		else
			hr = E_FAIL;		
		break;
	} 

	return TRUE;
}

BOOL CDlgViewHistory::OnInitDialog()
{
	CDialog::OnInitDialog();

	// TODO:  Add extra initialization here

	CWnd* pTT = m_wndHistory.FromHandle((HWND) m_wndHistory.SendMessage(TVM_GETTOOLTIPS));
	if (pTT != NULL)
		pTT->SetWindowPos(&CWnd::wndTopMost, 0, 0, 0, 0,
		SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE);

	CImageList img;
	img.Create(16, 16, ILC_COLORDDB|ILC_MASK, 4, 1);
	HBITMAP hbmp = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_HISTRORY_TREE));
	ImageList_AddMasked(img.GetSafeHandle(), hbmp, RGB(255,0,255));
	DeleteObject(hbmp);
	m_wndHistory.SetImageList(&img, TVSIL_NORMAL);
	img.Detach();

	Initialize();

	return TRUE;  // return TRUE unless you set the focus to a control
	// EXCEPTION: OCX Property Pages should return FALSE
}

void CDlgViewHistory::OnSize(UINT nType, int cx, int cy)
{
	CDialog::OnSize(nType, cx, cy);

	if (m_wndHistory.GetSafeHwnd())
		m_wndHistory.MoveWindow(0, 0, cx, cy);
	// TODO: Add your message handler code here
}

BOOL CDlgViewHistory::PreTranslateMessage(MSG* pMsg)
{
	// TODO: Add your specialized code here and/or call the base class
	if (pMsg->message == WM_MOUSEMOVE)
	{
		if (pMsg->hwnd == m_wndHistory.GetSafeHwnd())
		{
			HTREEITEM hItem;

			try
			{
				CPoint pt;
				GetCursorPos(&pt);
				ScreenToClient(&pt);
				hItem = m_wndHistory.HitTest(pt);

				if ((hItem != NULL) && !m_wndHistory.ItemHasChildren(hItem))
				{
					int nImg, nOImg;
					m_wndHistory.GetItemImage(hItem, nImg, nOImg);
					if(nImg == 2)
					{
						((CMainFrame*)AfxGetMainWnd())->SetStatusText(
							m_arrHistory[m_wndHistory.GetItemData(hItem) - 1]
						);
					}
				}			
			}
			catch(...)
			{

			}
		}
	}

	return CDialog::PreTranslateMessage(pMsg);
}
